package compoundDB.io;

import compoundDB.core.*;

import java.io.*;
import java.util.List;

/**
 * This interface specifies the standard for classes that can be plugged
 * into CompoundDB to add support for reading additional file types.
 * 
 * In addition to the interface requirements, implementors are required
 * to supply a no-argument constructor to create a new reader.
 * 
 * @author James Bridgwater
 *
 */
public interface MoleculeReader {

	/**
	 * Indicates whether the MoleculeReader supports multiple-molecule files.
	 * 
	 * @return true if the reader supports multiple compounds in a single file, otherwise false.
	 */
	public boolean multiMolecule();
	
	/**
	 * Returns a list of all filetypes supported by the reader.
	 * 
	 * @return A list of strings (of the form ".ext") corresponding to the extensions of filetypes that this reader supports.
	 */
	public List<String> supportedTypes();
	
	/**
	 * Opens a file for reading.
	 * 
	 * @param filename The name of the file to open for reading.
	 * @throws FileNotFoundException If the file does not exist or could not be opened.
	 */
	public void open(String filename) throws FileNotFoundException;
	
	/**
	 * Opens a file for reading, with the specified flags.
	 * 
	 * @param filename The name of the file to open.
	 * @param flags The flags to open the file with.
	 * @throws FileNotFoundException If the the file does not exist or could not be opened.
	 * @throws IllegalArgumentException If the flag combination is not valid for this object - e.g. FileMode.WRITE
	 * on a MoleculeReader that does not support writing.
	 */
	public void open(String filename, FileMode flags) throws FileNotFoundException, IllegalArgumentException; 
	
	/**
	 * Closes an open file.
	 */
	public void close();
	
	/**
	 * Indicates whether the reader has a file open for reading or not.
	 * 
	 * @return true if a file is open; false if no file has been opened or the file has been closed.
	 */
	public boolean isOpen();
	
	/**
	 * Reads the next compound in the file and returns it.
	 * 
	 * @return The next compound in the file, or null if there are no more compounds in the file.
	 * @throws IOException If an I/O error occurs
	 */
	public Compound readCompound() throws IOException;
	
	/**
	 * Indicates whether there are more compounds in the file or not.
	 * 
	 * @return true if there are more compounds in the file, otherwise false.
	 * @throws IOException If an I/O error occurs
	 */
	public boolean hasNext() throws IOException;
	
	/**
	 * Gives an indication of the total number of compounds in the file.
	 * 
	 * @return An estimate of the total number of compounds. There is guaranteed to be at least
	 * this number of compounds, but there may be more.
	 * @throws IOException If an I/O error occurs
	 */
	public int numberOfCompounds() throws IOException;
	
	/**
	 * Gives an indication of the number of remaining compounds in the file - that is, how many times
	 * <code>readCompound()</code> could be called before reaching the end of the file.
	 * 
	 * @return An estimate of the number of compounds remaining. There is guaranteed to be at least
	 * this number of compounds left, but there may be more. This is also guaranteed to be nonzero if
	 * there are any compounds remaining.
	 * @throws IOException If an I/O error occurs
	 */
	public int compoundsRemaining() throws IOException;
	
	/**
	 * Returns a list of every compound in the file, up to the specified limit.
	 * 
	 * @param limit The maximum number of compounds to return. If there are fewer than <code>limit</code> compounds in the file,
	 * all of them should be returned. If there are more, then the first <code>limit</code> of them after the current file position
	 * should be returned.
	 * @return A list of all names of compounds in the file, in the order they appear.
	 * @throws IOException If an I/O error occurs
	 */
	public List<String> listCompounds(int limit) throws IOException;
	
	/**
	 * Indicates the current position in the file. This should be zero initially, and increase by 1 for each molecule read.
	 * 
	 * @return The current position.
	 * @throws IOException If an I/O error occurs
	 */
	public int position() throws IOException;
	
	/**
	 * Moves to the specified position in the file. Seeking to 0 should move to the beginning of the file, seeking to 1 should
	 * move to just after the first compound in the file, and so on. Seeking to a negative index should move to the beginning,
	 * and seeking to a position beyond the last compound should move to the end of the file.
	 * @param position The position to seek to
	 * @throws IOException If an I/O error occurs
	 */
	public void seek(int position) throws IOException;
}
